//
//  ZYNotificationCenter.m
//  Example
//
//  Created by wzp on 2024/8/21.
//

#import "ZYNotificationCenter.h"

@interface ZYNotificationCenter() {
    NSMutableDictionary *_clientsMap;
    NSMutableDictionary *_keysMap;
}
@property (nonatomic, strong, nullable) NSLock *notifyLock;
@end

@implementation ZYNotificationCenter
+ (instancetype)shareInstance
{
    static id _instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (instancetype)init
{
    if (self = [super init]) {
        _clientsMap = [NSMutableDictionary dictionary];
        _keysMap = [NSMutableDictionary dictionary];
    }
    return self;
}


- (NSArray<ZYNotifyClient *> *)clientsWithKey:(nonnull Protocol *)ptl
{
    [self.notifyLock lock];
    NSArray<ZYNotifyClient *> *notifyList = [[_clientsMap objectForKey:NSStringFromProtocol(ptl)] copy];
    if (notifyList == nil) {
        notifyList = [NSMutableArray array];
        [_clientsMap setObject:notifyList forKey:NSStringFromProtocol(ptl)];
    }
    [self.notifyLock unlock];
    return [notifyList copy];
}

- (void)addClient:(id)client protocol:(Protocol *)ptl
{
    [_notifyLock lock];
    if ([client conformsToProtocol:ptl]) {
        NSMutableArray *clientList = _clientsMap[NSStringFromProtocol(ptl)];
        if (!clientList) {
            clientList = [NSMutableArray array];
        }
        ZYNotifyClient *notify = [[ZYNotifyClient alloc] init];
        notify.obj = client;
        [clientList addObject:notify];
    }
    [_notifyLock unlock];
}

- (void)removeAllForClient:(id)client
{
    if (!client) {
        return;
    }
    [_notifyLock lock];
    for (id key in _clientsMap.allKeys) {
        NSMutableArray *originList = _clientsMap[key];
        NSMutableArray *willRemoveList = [NSMutableArray array];
        for (ZYNotifyClient *notify in originList) {
            if (notify.obj == nil || notify.obj == client) {
                [willRemoveList addObject:notify];
            }
        }
        [originList removeObjectsInArray:willRemoveList];
    }
    [_notifyLock unlock];
}

- (void)removeClient:(id)client forProtocol:(Protocol *)ptl
{
    if (!client) {
        return;
    }
    [_notifyLock lock];
    NSMutableArray *originList = [_clientsMap objectForKey:NSStringFromProtocol(ptl)];
    NSArray *copyList = [originList copy];
    for (ZYNotifyClient *notify in copyList) {
        if (notify.obj == client || notify.obj == nil) {
            [originList removeObject:notify];
        }
    }
    
    [_notifyLock unlock];
}


- (NSLock *)notifyLock
{
    if (!_notifyLock) {
        _notifyLock = [[NSLock alloc] init];
    }
    return _notifyLock;
}
@end
